package org.osami.commons.smarthome.programnotifier;

import java.util.*;
//import javax.xml.parsers.*;
import java.io.*;
import java.text.SimpleDateFormat;
import org.kxml.*;
import org.kxml.parser.*;
import org.osami.commons.smarthome.settopbox.ISetTopBoxComponent;
import org.osgi.framework.ServiceReference;

public class ProgramDatabase {

	private Vector elements = new Vector();
	private static ProgramDatabase instance = null;
	private static SimpleDateFormat	df = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
	private Vector alerts = new Vector();
	BufferedReader reader;
		
	public ProgramDatabase() {

		System.out.println("Program database starting...");

	}
	
	protected void finalize() {
		System.out.println("Program database closing...");
	}
	
	public static ProgramDatabase getInstance() {
	
		if (null == instance)
			instance = new ProgramDatabase();
	
		return instance;
	}
	
	private void addElement(ProgramInfo element) {
		if (null != element) {
			elements.add(element);
		
		}
	}
	
	public void update() {
		Date now = Calendar.getInstance().getTime();
		
		while (elements.size() > 0 && ((ProgramInfo)elements.get(0)).getEndTime().before(now))
			elements.remove(0);
	}
	
	public void print() {
		System.out.println("Data base contains now:\n=======================================");
		for (int i = 0; i < elements.size(); i++) {
			((ProgramInfo)elements.get(i)).print();
			System.out.println("--------------------------------");
		}
		System.out.println("End of database.");
	}
		
	private void addAlerts()
	{
		System.out.println("ProgramDatabase: Creating alerts for interesting programs...");
		Calendar currentTime = Calendar.getInstance();
		int alertCounter = 0;
		
		for (int i = 0; i < elements.size(); i++) {
		
			long alertTime = ((ProgramInfo) elements.get(i)).getStartTime().getTime()-15000*60; // alert will fire 15 minutes before program starts				
			Calendar realAlertTime = Calendar.getInstance();
			realAlertTime.setTimeInMillis(alertTime);
			
			if (realAlertTime.compareTo(currentTime) > 0 )
			{
				ProgramInfo originalInfo = (ProgramInfo) elements.get(i);
				String [] deviceIDs = originalInfo.getDeviceId().split(",");
				for(int j=0; j< deviceIDs.length; j++)
				{
					ProgramInfo temp = new ProgramInfo();
						
					temp.setDeviceId(deviceIDs[j]);
					
					temp.setChannel(originalInfo.getChannel());
					temp.setDuration(originalInfo.getDuration());
					temp.setEndTime(originalInfo.getEndTime());
					temp.setId(originalInfo.getId());
					temp.setName(originalInfo.getName());
					temp.setServiceReference(originalInfo.getServiceReference());
					temp.setStartTime(originalInfo.getStartTime());
					
					// This is for real use
					alerts.add( new ProgramAlert (temp, realAlertTime.getTime() ));
					
					// This is for testing purposes, creates alerts immediately
					//alerts.add( new ProgramAlert (temp, currentTime.getTime() ));
					//System.out.println("ProgramDatabase: Alert time for <"+temp.getName()+"> is " + df.format(realAlertTime.getTime())+", deviceId : <"+temp.getDeviceId()+">" );
					alertCounter++;
				}
				//alerts.add( new ProgramAlert ((ProgramInfo) elements.get(i), realAlertTime.getTime() ));
				//System.out.println("ProgramDatabase: alert time for "+((ProgramInfo) elements.get(i)).getName()+" is " + df.format(realAlertTime.getTime()) );
				
			}							
		}
		System.out.println("ProgramDatabase: Totally "+alertCounter+" alerts added! " );
	}

	
	// This is new version
	public synchronized void reload() {
		elements.clear();
		
		ISetTopBoxComponent setTopBoxComponent = null;
		Hashtable programList = new Hashtable();
		
		
		try {
	
			programList = this.MyOtherXmlParser(new FileInputStream(new File("/media/hdd/programList.xml")));
			//programList = this.MyOtherXmlParser(new FileInputStream(new File("/media/hdd/alertList.xml")));
			
			String searchReply = "";
			
			System.out.println("ProgramDatabase: finding interesting services to handle recording...");
			ServiceReference ref = Activator.getBundleContext().getServiceReference(ISetTopBoxComponent.class.getName());
			if (null == ref) {
				System.out.println("ProgramDatabase: SetTopBox service not found");
			} else {
				setTopBoxComponent = (ISetTopBoxComponent)Activator.getBundleContext().getService(ref);
			}
			
			if (setTopBoxComponent!=null && programList!=null)
			{
				System.out.println("ProgramDatabase: SetTopBox service found");
							
				for (Enumeration e = programList.keys() ; e.hasMoreElements() ;)
				{
					String programName = (String)e.nextElement();
					//System.out.println("ProgramDatabase: programName: "+programName);
					searchReply = setTopBoxComponent.searchProgramByName(programName);
					InputStream is = new ByteArrayInputStream( searchReply.getBytes() );
					//System.out.println("ProgramDatabase: programList "+programList.get(programName));
					this.MyXmlParser(is, (String)programList.get(programName));						
				}
			}
			else
			{
				System.out.println("ProgramDatabase: ERROR!");
				return;
			}	
			this.addAlerts();
			
		} catch (Exception ex) {
			System.out.println("Error in ProgramDatabase.reload(): " + ex.getMessage());
			ex.printStackTrace();
		} 
		System.out.println("ProgramDatabase: Totally "+ elements.size()+" elements added into database." );
	}
	/*
	// This is the old one but still working version
	public synchronized void reload() {
		elements.clear();
		
		ISetTopBoxComponent setTopBoxComponent = null;
		
		try {
				     
			reader = new BufferedReader(new FileReader("/media/hdd/setup.ini"));
	        List<String> lines = new ArrayList<String>();
	        String line = null;
	        while ((line = reader.readLine()) != null) {
	            lines.add(line);
	            System.out.println("ProgramDatabase: Interesting Programs: "+line);
	        }
	        reader.close();
	        String [] searchText = lines.toArray(new String[lines.size()]);
						
			String reply = "";
			
			//XmlParser parser = new XmlParser(new InputStreamReader(new FileInputStream(new File("/media/hdd/osamiepgtest.xml"))), 300);
			
			System.out.println("ProgramDatabase: finding interesting services to handle recording...");
			ServiceReference ref = Activator.getBundleContext().getServiceReference(ISetTopBoxComponent.class.getName());
			if (null == ref) {
				System.out.println("ProgramDatabase: SetTopBox service not found");
			} else {
				setTopBoxComponent = (ISetTopBoxComponent)Activator.getBundleContext().getService(ref);
			}
			
			if (setTopBoxComponent!=null && searchText!=null)
			{
				System.out.println("ProgramDatabase: SetTopBox service found");
				for (int i=0; i<searchText.length; i++)
				{
					//System.out.println(searchText[i].length());
					if (searchText[i].length()>=2) // Search text must be at least 2 character long.
					{
						reply = setTopBoxComponent.searchProgramByName(searchText[i]);
						InputStream is = new ByteArrayInputStream( reply.getBytes() );
						this.MyXmlParser(is);
						
					}
					else
						System.out.println("ProgramDatabase: Search text "+searchText[i]+" was too short: "+searchText[i].length());
				}
			}
			else
			{
				System.out.println("ProgramDatabase: ERROR!");
				return;
			}	
			this.addAlerts();
			
		} catch (Exception ex) {
			System.out.println("Error in ProgramDatabase.reload(): " + ex.getMessage());
			ex.printStackTrace();
		} 
		System.out.println("DONE, " + elements.size());
	}
	*/
	public SimpleDateFormat getDateFormat() {
		return df;
	}
	
	
	// This is the original version
	private void MyXmlParser (InputStream is, String deviceId) throws IOException{
		
		XmlParser parser = new XmlParser(new InputStreamReader(is));
		ParseEvent event = null;
		String currentElement = "";
		ProgramInfo currentProgram = null;
		long unixStartTime = 0;
		
		//System.out.println("ProgramDatabase: XMLParser starts");
		//System.out.println("ProgramDatabase: deviceID "+deviceId);
		while((event = parser.read()).getType() != Xml.END_DOCUMENT){
			
			if(event.getType() == Xml.START_TAG){
				currentElement = event.getName();
				//System.out.println("ProgramDatabase: currentElement: "+currentElement);
				
				if (currentElement.equals("e2event")) {
					
					currentProgram = new ProgramInfo();
					addElement(currentProgram);
					
					currentProgram.setDeviceId(deviceId.trim());
					
					currentElement = "";
				}
				
			}
			else if (event.getType() == Xml.TEXT)
			{
				String data = event.getText().trim();
				//System.out.println("ProgramDatabase: data: "+data);
				
				if (data.length() < 1)
					continue;
								
				if (currentElement.equals("e2eventid")) {
					
					currentProgram.setId(Integer.parseInt(data));
					currentElement = "";
				}
				else if (currentElement.equals("e2eventstart")) {
					unixStartTime = Long.parseLong(data);
					Calendar eventStartTime = Calendar.getInstance();
					eventStartTime.setTimeInMillis(unixStartTime*1000);
															    						
					try
					{
						currentProgram.setStartTime(eventStartTime.getTime());
					}
					catch (Exception ex)
					{
						System.out.println("Error in date parsing: " + ex.getMessage());
					}
					
					currentElement = "";
				}
				else if (currentElement.equals("e2eventduration")) {
					int duration = Integer.parseInt(data); 
					currentProgram.setDuration(duration);
					
					// Calculating program end time
					Long longduration = (Long)(long)duration;

					long unixEndTime = unixStartTime + longduration ;  // msec  
					Calendar eventEndTime = Calendar.getInstance();
					eventEndTime.setTimeInMillis(unixEndTime*1000);
									    						
					try
					{
						currentProgram.setEndTime(eventEndTime.getTime());
					}
					catch (Exception ex)
					{
						System.out.println("Error in date parsing: " + ex.getMessage());
					}
					currentElement = "";
				}
				else if (currentElement.equals("e2eventtitle")) {
						currentProgram.setName(data);
						currentElement = "";
				}
				else if (currentElement.equals("e2eventservicereference")) {
					currentProgram.setServiceReference(data);
					currentElement = "";
				}
				else if (currentElement.equals("e2eventservicename")) {
					currentProgram.setChannel(data);
					currentElement = "";
				}
				else if (1 == 2) {
					// If you love OSAmI send a SMS containing "Pasi nyt töihin" to +358403514858
				}				
				
			}
			
			event = null;
		}
		//System.out.println("ProgramDatabase: XMLParser is ready");
	}
	
	/*
	// The improved parser
	private void MyXmlParser (InputStream is, String deviceId) throws IOException{
		
		XmlParser parser = new XmlParser(new InputStreamReader(is));
		ParseEvent event = null;
		String currentElement = "";
		ProgramInfo currentProgram = null;
		long unixStartTime = 0;
		
		//System.out.println("ProgramDatabase: XMLParser starts");
		//System.out.println("ProgramDatabase: deviceID "+deviceId);
		while((event = parser.read()).getType() != Xml.END_DOCUMENT){
			
			if(event.getType() == Xml.START_TAG){
				currentElement = event.getName();
				//System.out.println("ProgramDatabase: currentElement: "+currentElement);
				
				if (currentElement.equals("e2event")) {
					
					currentProgram = new ProgramInfo();
					addElement(currentProgram);
					
					currentProgram.setDeviceId(deviceId.trim());
					
					currentElement = "";
				}
				
			}
			else if (event.getType() == Xml.TEXT)
			{
				String data = event.getText().trim();
				//System.out.println("ProgramDatabase: data: "+data);
				
				if (data.length() < 1)
					continue;
								
				if (currentElement.equals("e2eventid")) {
					
					currentProgram.setId(Integer.parseInt(data));
					currentElement = "";
				}
				else if (currentElement.equals("e2eventstart")) {
					unixStartTime = Long.parseLong(data);
					Calendar eventStartTime = Calendar.getInstance();
					eventStartTime.setTimeInMillis(unixStartTime*1000);
															    						
					try
					{
						currentProgram.setStartTime(eventStartTime.getTime());
					}
					catch (Exception ex)
					{
						System.out.println("Error in date parsing: " + ex.getMessage());
					}
					
					currentElement = "";
				}
				else if (currentElement.equals("e2eventduration")) {
					int duration = Integer.parseInt(data); 
					currentProgram.setDuration(duration);
					
					// Calculating program end time
					Long longduration = (Long)(long)duration;

					long unixEndTime = unixStartTime + longduration ;  // msec  
					Calendar eventEndTime = Calendar.getInstance();
					eventEndTime.setTimeInMillis(unixEndTime*1000);
									    						
					try
					{
						currentProgram.setEndTime(eventEndTime.getTime());
					}
					catch (Exception ex)
					{
						System.out.println("Error in date parsing: " + ex.getMessage());
					}
					currentElement = "";
				}
				else if (currentElement.equals("e2eventtitle")) {
						currentProgram.setName(data);
						currentElement = "";
				}
				else if (currentElement.equals("e2eventservicereference")) {
					currentProgram.setServiceReference(data);
					currentElement = "";
				}
				else if (currentElement.equals("e2eventservicename")) {
					currentProgram.setChannel(data);
					currentElement = "";
				}
				else if (1 == 2) {
					// If you love OSAmI send a SMS containing "Pasi nyt töihin" to +358403514858
				}				
				
			}
			
			event = null;
		}
		//System.out.println("ProgramDatabase: XMLParser is ready");
	}
	*/
	/*
	 // This is the improved one
	private Hashtable MyOtherXmlParser (InputStream is) throws IOException{
		
		XmlParser parser = new XmlParser(new InputStreamReader(is));
		ParseEvent event = null;
		Hashtable programAlerts = new Hashtable();
		String currentElement = "";
		String progName = "";
		String deviceId = "";
		
		System.out.println("ProgramDatabase: keyword XMLParser starts");
		while((event = parser.read()).getType() != Xml.END_DOCUMENT){
			
			//System.out.println("name: "+event.getName() +" type: "+ event.getType());
			
			
			if(event.getType() == Xml.START_TAG){
			System.out.println(event.getName());
			
			
				if (event.getName().equals("programAlert")) {
										
					progName = event.getAttribute("programName").getValue();
															
									
					if(programAlerts.get(progName) != null)
					{
						//TODO: ensure that a device cannot be entered many times under one key
						deviceId = deviceId+","+event.getValue("deviceId");
						programAlerts.put(progName, deviceId); //update this key
					}
					else
					{
						programAlerts.put(event.getAttribute("programName").getValue() , event.getAttribute("deviceId").getValue());
					}
				}
				
			}
			
			event = null;
		}
		System.out.println("ProgramDatabase: MyOtherXMLParser is ready");
		return programAlerts;
	}
	*/
	
	private Hashtable MyOtherXmlParser (InputStream is) throws IOException{
		
		XmlParser parser = new XmlParser(new InputStreamReader(is));
		ParseEvent event = null;
		Hashtable programAlerts = new Hashtable();
		String currentElement = "";
		
		//System.out.println("ProgramDatabase: keyword XMLParser starts");
		while((event = parser.read()).getType() != Xml.END_DOCUMENT){
			
			if(event.getType() == Xml.START_TAG){
				currentElement = event.getName();
				
				if (currentElement.equals("keyWord")) {
										
					String progName = event.getAttribute("programName").getValue();
					//System.out.println(progName);
					String deviceId = (String)programAlerts.get(progName);
					if(deviceId != null)
					{
						//TODO: ensure that a device cannot be entered many times under one key
						deviceId = deviceId+","+event.getAttribute("deviceId").getValue();
						programAlerts.put(progName, deviceId); //update this key
					}
					else
					{
						programAlerts.put(event.getAttribute("programName").getValue() , event.getAttribute("deviceId").getValue());
					}
					//System.out.println("ProgramDatabase.MyOthr.keyWords: "+programAlerts.toString());
					currentElement = "";
				}
				
			}
			
			event = null;
		}
		//System.out.println("ProgramDatabase: MyOtherXMLParser is ready");
		return programAlerts;
	}
	
}
